package net.beyondts.mplug;

import net.beyondts.mplug.utils.IOUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Project: mplug-project<br/>
 * Description: The manager of plugins configuration file. This is used by PluginManager.<br/>
 * Created at: 2019-1-12<br/>
 * Owned by beyondts.
 *
 * @author blazecrystal
 * @version 1.0.0
 */
public class PluginsConfig {
    private String configFilePath;
    private List<String> enabledPlugins;
    
    private static final String CHARSET = "UTF-8";

    /**
     * Read the config file of outside plugins.
     * @param pluginsDir String the directory path of plugins' base directory
     * @return PluginsConfig new instance of current class
     * @throws IOException ...
     */
    public static PluginsConfig readConfig(String pluginsDir) throws IOException {
        String configPath = pluginsDir + "config" + File.separator + "plugins";
        PluginsConfig config = new PluginsConfig(configPath);
        InputStream is = null;
        try {
            is = new FileInputStream(configPath);
            config.read(is);
        } finally {
            IOUtils.closeQuietly(is);
        }
        return config;
    }

    /**
     * Read the config file of default plugins.
     * @return PluginsConfig new instance of current class
     * @throws IOException ...
     */
    public static PluginsConfig readDefaultConfig() throws IOException {
        PluginsConfig config = new PluginsConfig();
        config.read(ClassLoader.getSystemResourceAsStream("plugins/config/plugins.default"));
        return config;
    }

    /**
     * remove a plugin from config file (just for outside plugins).
     * @param pluginInfo PluginInfo infomation of plugin which needs be removed
     * @throws IOException ...
     */
    public void removePluginFromConfig(PluginInfo pluginInfo) throws IOException {
        String plugin = pluginInfo.getArtifactId() + "-" + pluginInfo.getVersion();
        if (enabledPlugins.contains(plugin)) {
            enabledPlugins.remove(plugin);
            write();
        }
    }

    /**
     * add a plugin to config file (just for outside plugins).
     * @param pluginInfo PluginInfo infomation of plugin which needs be removed
     * @throws IOException ...
     */
    public void addPluginToConfig(PluginInfo pluginInfo) throws IOException {
        String plugin = pluginInfo.getArtifactId() + "-" + pluginInfo.getVersion();
        if (!enabledPlugins.contains(plugin)) {
            enabledPlugins.add(plugin);
            write();
        }
    }

    public List<String> getEnabledPlugins() {
        return enabledPlugins;
    }

    private PluginsConfig() {
        this.enabledPlugins = new ArrayList<>();
    }

    private PluginsConfig(String configFilePath) {
        this.configFilePath = configFilePath;
        this.enabledPlugins = new ArrayList<>();
    }

    private void read(InputStream is) throws IOException {
        BufferedReader br = null;
        try {
            br = new BufferedReader(new InputStreamReader(is, CHARSET));
            String line = null;
            while((line = br.readLine()) != null) {
                line = line.trim();
                if (StringUtils.isNotBlank(line)) {
                    enabledPlugins.add(line);
                }
            }
        } finally {
            IOUtils.closeQuietly(br);
        }
    }
    
    private void write() throws IOException {
        PrintWriter pw = null;
        try {
            pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(configFilePath), CHARSET), true);
            if (enabledPlugins.size() < 1) {
                pw.print("");
            } else {
                for (int i = 0; i < enabledPlugins.size(); i++) {
                    pw.print(enabledPlugins.get(i));
                    if (i < enabledPlugins.size()) {
                        pw.println();
                    }
                }
            }
            pw.flush();
        } finally {
            IOUtils.closeQuietly(pw);
        }
    }
}
